package com.woniuxy.shiro;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;

/**
 * 自定义过滤器，用于jwt认证的校验
 */
@Slf4j
public class JwtFilter extends AuthenticatingFilter {

    @Autowired
    private ApplicationContext applicationContext;
    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        String jwtToken = ((HttpServletRequest)servletRequest).getHeader("jwt");
        return new JwtToken(jwtToken);
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        return false;
    }

    /**
     * shiro过滤器的控制器，让isAccessAllowed来处理所以的过滤请求
     * @param request
     * @param response
     * @param mappedValue
     * @return
     * @throws Exception
     */
    @Override
    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        return isAccessAllowed(request, response, mappedValue);
    }

    /**
     * 为jwt自动续期
     * @param token
     * @param subject
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        return super.onLoginSuccess(token, subject, request, response);
    }

    /**
     * 处理所有过滤请求，除非这不是最后一个过滤器，否则返回false并给网关发送消息放行
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (this.isLoginRequest(request, response))
            return true;
        boolean allowed = false;
        try {
            allowed = executeLogin(request, response);
        } catch (IllegalStateException e) { // not found any token
            log.error("Not found any token");
        } catch (Exception e) {
            log.error("Error occurs when login", e);
        }
        ShiroFilterFactoryBean shiroFilterFactoryBean = applicationContext.getBean(ShiroFilterFactoryBean.class);

        response.setContentType("application/json");
        try{
            if (allowed){
                //获取当前访问的url
                String url = ((HttpServletRequest)request).getRequestURI().toString();
                //如果是访问本项目的url就放行
                if (url.contains("adminUser")){
                    return true;
                }
                log.info(url);
                //获取url所需经过的过滤器
                Map<String ,String> filterMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
                //这里根据拿到的值进行字符串分割，这个值的字符串样式可能为jwt,perms[]，可能有多个过滤器
                String[] filters = filterMap.get(url).replaceAll("\\[([^\\[\\]]*)\\]","").split(",");
                //根据过滤器的名字找到具体的过滤器的类
                Map<String, Filter> map = shiroFilterFactoryBean.getFilters();
                //判断当前的过滤器类是否是该URL所需过滤器中的最后一个
                Filter lastFilter = map.get(filters[filters.length-1]);
                if (lastFilter.getClass()==this.getClass()){
                    log.info("过滤器返回网关成功消息");
                    ObjectMapper objectMapper = new ObjectMapper();
                    response.getWriter().write(objectMapper.writeValueAsString(ResponseResult.SUCCESS));
                }else {
                    //如果是最后一个就返回false，不是就返回true继续走
                    return true;
                }
            }else {
                log.info("会话失效重新登录");
                ResponseResult<Void> result = new ResponseResult<>(403,"jwt is error");
                ObjectMapper objectMapper = new ObjectMapper();
                response.getWriter().write(objectMapper.writeValueAsString(result));
                log.info("消息发送成功");
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("Jwt过滤器拒绝了你的访问");
        return false;
    }
}
